﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace Pingy
{
    public class WHOISServers
    {
        public const string Ripe = "whois.ripe.net";
        public const string ARIN = "whois.arin.net";
        public const string Internic = "whois.internic.net";
    }

    public class Network
    {
        public static IPHostEntry GetHostInfo(string address)
        {
            try
            {
                return Dns.GetHostEntry(address);
            }
            catch (SocketException ex)
            {
                return null;
            }
        }


        /// <summary>
        /// Does the actual lookup against the given whois host using the
        /// supplied search text. Note that I split the functionality of this methods
        /// into three distinct parts each in their own try/catch block so that error
        /// codes reported to the (l)user can be a bit more precise.
        /// </summary>
        /// <param name="searchText">The text to use for search criteria</param>
        ///
        public static string WHOIS(string address, string server)
        {
            if (address == null)
                throw new ArgumentNullException("address", "Address information cannot be null");
            int portNumber = 43; // whois is always on port 43

            try
            {

                string response = "";

                TcpClient theConnection = new TcpClient(server, portNumber);
                using (NetworkStream networkStream = theConnection.GetStream())
                {
                    using (BufferedStream bfStream = new BufferedStream(networkStream))
                    {
                        StreamWriter outputStream = new StreamWriter(bfStream);
                        outputStream.WriteLine(address); // off it goes
                        outputStream.Flush();

                        StreamReader inputStream = new StreamReader(bfStream);
                        string intermediateOutput;
                        while ((intermediateOutput = inputStream.ReadLine()) != null)
                        {
                            response += intermediateOutput + "\r\n";
                        }
                    }
                }
                theConnection.Close();

                return response;
            }
            catch (IOException ex)
            {
                return "Unable to query WHOIS server: " + ex.Message;
            }
            catch (SocketException se)
            {
                return "Unable to query WHOIS server: " + se.Message;
            }
        }
    }

    public enum IPVersion
    {
        IPv4,
        IPv6,
    }

    public class IPRange : IEnumerable<IPAddress>
    {
        private Subnet[] subnets = new Subnet[4];
        public Subnet[] Subnets
        {
            get { return subnets; }
            set { subnets = value; }
        }

        #region IEnumerable<IPAddress> Members

        public IEnumerator<IPAddress> GetEnumerator()
        {
            return new IPAddressEnumerator(subnets);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new IPAddressEnumerator(subnets);
        }

        #endregion

        public class IPAddressEnumerator : IEnumerator<IPAddress>
        {
            private Subnet[] subnets;

            private bool isInitialized = false;

            byte a;
            byte b;
            byte c;
            byte d;

            public IPAddressEnumerator(Subnet[] subnets)
            {
                this.subnets = subnets;
            }

            #region IEnumerator<IPAddress> Members

            IPAddress current;
            public IPAddress Current
            {
                get { return current; }
            }

            #endregion

            #region IEnumerator Members

            object System.Collections.IEnumerator.Current
            {
                get { return current; }
            }

            public bool MoveNext()
            {
                if (!isInitialized)
                    Reset();
                else
                {
                    if (d == byte.MaxValue)
                        return false;
                    d++;

                    if (d > subnets[3].End)
                    {
                        d = subnets[3].Start;

                        if (c == byte.MaxValue)
                            return false;
                        c++;
                    }
                    if (c > subnets[2].End)
                    {
                        c = subnets[2].Start;

                        if (b == byte.MaxValue)
                            return false;
                        b++;
                    }
                    if (b > subnets[1].End)
                    {
                        b = subnets[1].Start;

                        if (a == byte.MaxValue)
                            return false;
                        a++;
                    }
                    if (a > subnets[0].End)
                    {
                        return false;
                    }
                }

                current = new IPAddress(new byte[] { a, b, c, d });
                return true;
            }

            public void Reset()
            {
                a = subnets[0].Start;
                b = subnets[1].Start;
                c = subnets[2].Start;
                d = subnets[3].Start;
                isInitialized = true;
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {

            }

            #endregion
        }
    }

    public class Subnet
    {
        byte startValue;
        public byte Start
        {
            get { return startValue; }
            set { startValue = value; }
        }

        byte endValue;
        public byte End
        {
            get { return endValue; }
            set { endValue = value; }
        }

        public Subnet()
        {
        }

        public Subnet(byte value)
        {
            startValue = value;
            endValue = value;
        }

        public Subnet(byte startValue, byte endValue)
        {
            this.startValue = startValue;
            this.endValue = endValue;
        }
    }
}

